﻿#pragma once
#include <QWidget>
#include <QTransform>
#include <QPainter>
#include <QMouseEvent>
#include <QWheelEvent>
#include <QBasicTimer>
#include "../src_config/configUI.h"
#include "../src_dataProcessor/basicData.h"
#include "../src_algorithms/algorithms.h"

class DiagramWidget : public QWidget {
	Q_OBJECT
public:
	explicit DiagramWidget(BasicData* data, ConfigUI* conf, QWidget* parent);
	~DiagramWidget();

public:
	BasicData* m_data;
	Algorithoms* m_alg;
	QString m_qFilePath;
	QString m_qFileName;
	int m_data_type = 0;	//1 为解析图片map，2 为post文件，3为文本map

public:	//槽函数，接收到相应信号时被触发
	void action_reset();					// 复位重置（仅针对读取map类的txt文件）
	void action_random_pin();				// 重新生成随机pin
	void pin_decrease();					// pin数量减少
	void action_pin_increase();				// pin数量增加
	void action_save_case();				// 保存case
	void action_save_image();				// 保存图片
	void action_write_pre();				// 保存预处理结果
	void action_write_res();				// 在预处理结果后面追加结果


	void action_write_after_post();

	void initViewTransform();  //视图初始化函数,构造时会触发,添加一条数据也需触发

private:
	//当前窗口相关的文件信息

	QString m_qFullSaveName;	//保存的文件名
	bool m_resAdded = true;;	//结果是否被追加到文件后面


private:	//########################## 绘图模块 ##########################
	//0.选项信息
	ConfigUI* m_config;	//配置信息

	//0.1绘图核心参数
	QRectF m_visibleRect;		//可见区域（实际数据）
	QTransform m_transform;		//变换矩阵，数据的实际坐标-->屏幕坐标
	qreal m_scaleFactor = 1.0;	//缩放倍数，数据的实际坐标-->屏幕坐标
	QPointF m_panOffset;		//缩放后的偏移量（屏幕坐标偏移量）

	QPoint m_pressPos;
	QPoint m_releasePos;
	QPoint m_movePos;

	//0.2 绘图缓存
	QPixmap m_canvasCache;      // 离屏缓存图像
	QPoint m_cacheOffset;       // 缓存相对于当前视图的偏移
	bool m_cacheValid = false;  // 缓存是否有效

	//1.可见区绘制，缓存绘制
	void paintVisibleContent(QPainter& painter, const QRect& rect);
	void paintCacheContent(QPainter& painter, const QRect& rect);

	//2.绘制各个模块
	void drawBackground(int r, int paintNetType, QPainter& painter);	//绘制背景网格
	void drawObstacles(int r, QPainter& painter);						//绘制障碍物

	//3.绘制点
	void drawPoints(QPointF point, int r, QPainter& painter);
	void drawPoints(LineUI line, int r, QPainter& painter);							 //绘制线段的端点
	void drawPoints(vector<QPointF>& points, int r, QPainter& painter);
	void drawPoints(vector<vector<QPointF>>& points, int r, QPainter& painter);
	void drawPoints(vector<LineUI>& lines, int r, QPainter& painter);				//绘制折线的端点（连续线段，只绘制一个）
	void drawPoints(vector<vector<LineUI>>& lines, int r, QPainter& painter);		//绘制折线的端点（连续线段，只绘制一个）
	void drawTwoPoints(vector<LineUI>& lines, int r, QPainter& painter);			//绘制线段的端点（绘制两个端点）
	void drawTwoPoints(vector<vector<LineUI>>& lines, int r, QPainter& painter);	//绘制折线的端点（连续线段，只绘制一个）

	//4.绘制线段
	void drawLines(LineUI& line, QPainter& painter);
	void drawLines(vector<LineUI>& lines, QPainter& painter);
	void drawLines(vector<vector<LineUI>>& lines, QPainter& painter);
	void drawLines(vector<vector<vector<LineUI>>>& lines, QPainter& painter);
	void drawLines(vector<vector<vector<vector<LineUI>>>>& lines, QPainter& painter);
	void drawLines(vector<QPointF>& points, QPainter& painter);
	void drawLines(vector<vector<QPointF>>& points, QPainter& painter);

	//5.辅助函数
	//5.1坐标转换接口
	QPointF dataToScreen(const QPointF& dataPoint) const;
	LineUI  dataToScreen(const LineUI& dataLine) const;
	QPointF screenToData(const QPointF& screenPoint) const;
	void updateTransform();

	//5.2线段裁剪
	bool clipLine(QPointF& p1, QPointF& p2, const QRectF& viewport) const;
	bool clipLine(LineUI& line, const QRectF& viewport) const;
	bool clipPt(QPointF& pt, const QRectF& viewport) const;




protected:	//########################## 事件管理 ##########################
	//1.综合事件
	void showEvent(QShowEvent* event) override;			//初始化显示
	void resizeEvent(QResizeEvent* event) override;		//resize
	void timerEvent(QTimerEvent* event) override;		//定时刷新
	void paintEvent(QPaintEvent* event) override;		//绘图事件

	//2.鼠标事件
	void mousePressEvent(QMouseEvent* event) override;
	void mouseMoveEvent(QMouseEvent* event) override;
	void mouseReleaseEvent(QMouseEvent* event) override;
	void wheelEvent(QWheelEvent* event) override;

	//3.事件执行
	void pressRun(const QPoint& pressPos);
	void moveRun();
	void releaseRun(const QPoint& releasePos);
	void wheelEventRun(const int& delta, const QPointF& screenPos);

private:	//########################## 事件执行 ##########################
	//0.参数准备
	//0.1推线参数
	struct SelectedLine {
		bool pinSelected = false;
		bool lineSelected = false;
		bool isPushPin = false;
		LineUI sLine;				// 选中的线段
		QPointF nearistPt;			// 捕捉最近的点
		vector<LineUI>* linesToRun;		// 选中的线段所在的折线
		QPointF offset;	// 点击点与线段起点的偏移量
		void clear() {
			pinSelected = false;
			lineSelected = false;
			isPushPin = false;
			sLine = LineUI(0, 0, 0, 0);
			nearistPt.setX(0);
			nearistPt.setY(0);
			offset.setX(0);
			offset.setY(0);
		}
	};
	SelectedLine m_slLine;
	QBasicTimer m_moveTimer;


	

	//鼠标按下时，执行一次的内容集合
	void setPushLines(const QPointF& clickPt);	//捕捉线
	void moveCanvasBegin(const QPointF& clickPt);

	//鼠标移动时，需持续执行的内容集合
	void pushLineActivate();
	void moveCanvasActivate();
	//鼠标释放时，执行一次的内容集合
	void pushLineEnd(const QPointF& releasePt);
	void moveCanvasEnd(const QPoint& releasePt);

	//吸附阈值(数据坐标
	bool setSelectedPt(const QPointF& clickPt, const LineUI& line, double snapThreshold);
	bool setSelectedPt(const QPointF& clickPt, vector<LineUI>& lines, double snapThreshold);
	bool setSelectedPt(const QPointF& clickPt, vector<vector<LineUI>>& lines, double snapThreshold);
	bool setSelectedPt(const QPointF& clickPt, vector<vector<vector<LineUI>>>& lines, double snapThreshold);

	bool setSelectedLine(const QPointF& clickPt, const LineUI& line, double snapThreshold);
	bool setSelectedLine(const QPointF& clickPt, vector<LineUI>& lines, double snapThreshold);
	bool setSelectedLine(const QPointF& clickPt, vector<vector<LineUI>>& lines, double snapThreshold);
	bool setSelectedLine(const QPointF& clickPt, vector<vector<vector<LineUI>>>& lines, double snapThreshold);


public:		//与算法相关的槽函数
	void setPPDTRun();
	void setPolyRun();
};